package com.fingard.dsp.bank.directbank.citic01;

import com.fingard.FGBiz;
import com.fingard.constant.Format;
import com.fingard.db.JDBCHelper;
import com.fingard.dsp.bank.directbank.PaymentState;
import com.fingard.dsp.bank.directbank.bankInterface.IForeignCurrency;
import com.fingard.dsp.bank.reqrespobj.foreigncurrsingle.ReqForeignCurrSingle;
import com.fingard.dsp.bank.reqrespobj.foreigncurrsingle.ReqQryForeignCurrSingle;
import com.fingard.dsp.bank.reqrespobj.foreigncurrsingle.RetAtsForeignCurrSingle;
import com.fingard.dsp.bank.reqrespobj.foreigncurrsingle.detail.RetAtsForeignCurrPayDetail;
import com.fingard.net.ConnState;
import com.fingard.text.StringHelper;
import com.fingard.xml.XElement;
import com.fingard.xml.XmlTextReader;
import com.fingard.xml.XmlTextWriter;

import java.sql.Connection;
import java.util.Date;
import java.util.Map;
import java.util.UUID;


public class CITIC01ForeignCurrSinglePay extends CITIC01Base implements IForeignCurrency {
    //URID,渠道，ATS流水号，业务类型
    private static final String INSERTRECEIPT = "INSERT INTO REQSEQIDMAPPING(URID,BANKCODE,REQSEQID,RESERVE1,TRANSDATE) values (?,?,?,?,?);";
    private static final String SELECTRECEIPT = "SELECT RESERVE1,TRANSDATE FROM REQSEQIDMAPPING WHERE REQSEQID=? AND BANKCODE=?;";

    /**
     * 外币汇款支付
     *
     * @param reqForeignCurrSingle
     * @return
     * @throws Exception
     */
    @Override
    public RetAtsForeignCurrSingle foreignCurrPay(ReqForeignCurrSingle reqForeignCurrSingle) throws Exception {
        RetAtsForeignCurrSingle retAts = new RetAtsForeignCurrSingle(reqForeignCurrSingle.reqHeader);
        RetAtsForeignCurrPayDetail tmpRetDetail = null;
        if ("DomesticFCP".equals(reqForeignCurrSingle.reqHeader.transType) || "CrossborderFCP".equals(reqForeignCurrSingle.reqHeader.transType)) {
            tmpRetDetail = d_DLOUTSUB(reqForeignCurrSingle);
        } else {
            tmpRetDetail = new RetAtsForeignCurrPayDetail();
            tmpRetDetail.respCode = "0";
            tmpRetDetail.respInfo = "无效的指令代码";
            tmpRetDetail.transState = PaymentState.FAIL_Payment;
            tmpRetDetail.payInfoCode = tmpRetDetail.transState;
        }
        retAts.writeRetDetail(tmpRetDetail);
        return retAts;
    }

    private RetAtsForeignCurrPayDetail d_DLOUTSUB(ReqForeignCurrSingle reqForeignCurrSingle) throws Exception {
        RetAtsForeignCurrPayDetail detail = new RetAtsForeignCurrPayDetail();
        Connection conn = FGBiz.getLocalDbConn();
        try {
            CITIC01Header bankHeader = new CITIC01Header();
            bankHeader.action = "DLOUTSUB";
            XmlTextWriter xmlWriter = new XmlTextWriter();//发银行报文的XML对象
            xmlWriter.writeStartDocByDeclaration("<?xml version=\"1.0\" encoding=\"GBK\"?>");
            XElement tmpXElement = new XElement("stream", "");
            tmpXElement.addChild(new XElement("action", bankHeader.action));
            tmpXElement.addChild(new XElement("userName", bankFront.loginName));//直联登录名
            tmpXElement.addChild(new XElement("clientID", reqForeignCurrSingle.singleDetail.askNumber));
            String unitCode = getBankConfig().getMapValueByKey("unitCodeMap", reqForeignCurrSingle.singleDetail.payCashAct);
            tmpXElement.addChild(new XElement("unitCode", StringHelper.isNullOrEmpty(unitCode) ? "" : unitCode));//国际业务办理网点 每个账户单独维护 没有就为空
            tmpXElement.addChild(new XElement("bsnType", reqForeignCurrSingle.singleDetail.fundsProp));//业务类型1：贸易；2：服务贸易；3：资本；4：同名划转
            tmpXElement.addChild(new XElement("outCryType", getBankConfig().getMapValueByKey("currencyMapping2", reqForeignCurrSingle.singleDetail.payCur)));//汇出款币种
            tmpXElement.addChild(new XElement("outAmt", reqForeignCurrSingle.singleDetail.payAmount));//汇出款金额
            tmpXElement.addChild(new XElement("valueDate", Format.Date8Format.format(new Date())));//报文起息日 格式YYYYMMDD，起息日不能小于当天-->系统当前日期
            tmpXElement.addChild(new XElement("remAccNo", reqForeignCurrSingle.singleDetail.payCashAct));//汇款账号1 -->现汇账号
            tmpXElement.addChild(new XElement("remAccNo2", ""));//汇款账号2 购汇账号 目前天马不使用购汇付款
            tmpXElement.addChild(new XElement("remCryType", getBankConfig().getMapValueByKey("currencyMapping2", reqForeignCurrSingle.singleDetail.payCur)));//汇款币种，与汇款账号1所属币种一致-->现汇账号对应的付款币种
            tmpXElement.addChild(new XElement("remCryType2", ""));//汇款币种2，可空，与汇款账号2所属币种一致
            tmpXElement.addChild(new XElement("etrnCurrAmt", reqForeignCurrSingle.singleDetail.payAmount));//折交易币别金额,不存在跨币种付款，因此此金额与汇款金额一致
            tmpXElement.addChild(new XElement("etrnCurrAmt2", ""));//折交易币别金额2,可空，当汇款账号2、汇款币种2不为空时必输
            String crePreCountry = "";
            if (!StringHelper.isNullOrEmpty(reqForeignCurrSingle.singleDetail.recCountryCode)) {
                crePreCountry = getBankConfig().getMapValueByKey("countryCode", reqForeignCurrSingle.singleDetail.recCountryCode);
                if (StringHelper.isNullOrEmpty(crePreCountry)) {
                    detail.respCode = "0";
                    detail.respInfo = "收款方常驻国家编码映射未找到！";
                    detail.reqSeqID = reqForeignCurrSingle.singleDetail.askNumber;
                    detail.transState = "countryConfigIsNull";
                    detail.payInfoCode = detail.transState;
                    return detail;
                }
            } else {
                detail.respCode = "0";
                detail.respInfo = "收方常驻国家必填！";
                detail.reqSeqID = reqForeignCurrSingle.singleDetail.askNumber;
                detail.transState = "recCountryMustInput";
                detail.payInfoCode = detail.transState;
                return detail;
            }
            tmpXElement.addChild(new XElement("rcvPreCountry", crePreCountry));//(测试时，发现必填)收款人常驻国家,传国家编码（配置文件映射）
            tmpXElement.addChild(new XElement("rBankAgeBIC", ""));//收款银行之代理行BIC---不传
            tmpXElement.addChild(new XElement("rBankNmOfAdd", ""));//收款银行之代理行名称及地址---不传
            tmpXElement.addChild(new XElement("rBankAcc", ""));//收款人开户银行在其代理行账号---不传
            tmpXElement.addChild(new XElement("rcvAcc", reqForeignCurrSingle.singleDetail.recAct));//收款人账号
            tmpXElement.addChild(new XElement("rcvNm", reqForeignCurrSingle.singleDetail.recName));//收款人名称
            tmpXElement.addChild(new XElement("rcvAddress", reqForeignCurrSingle.singleDetail.recAddr));//收款人地址 ，可空
            tmpXElement.addChild(new XElement("rBankBIC", reqForeignCurrSingle.singleDetail.recSWIFTCODE));//收款人银行BIC(传SWIFT CODE)/收款人银行名称地址 不能同时为空
            tmpXElement.addChild(new XElement("rBankAdd", reqForeignCurrSingle.singleDetail.cnapsName));//收款人银行名称地址/收款人银行BIC(传SWIFT CODE) 不能同时为空
            tmpXElement.addChild(new XElement("remPostscript", reqForeignCurrSingle.singleDetail.abstractATS));//汇款附言,可空(这里传ATS对账码)
            tmpXElement.addChild(new XElement("declareNo", reqForeignCurrSingle.singleDetail.costMode));//国内外费用承担 SHA：共同SHA；OUR：汇款人OUR;BEN：收款人BEA-->出纳选择，必填，必传银行
            String payType = reqForeignCurrSingle.singleDetail.payMethod;
            //付款类型1-预付货款2-货到付款3-退款4-其他 必填
            if ("A".equals(payType)) {
                tmpXElement.addChild(new XElement("payType", "1"));
            } else if ("P".equals(payType)) {
                tmpXElement.addChild(new XElement("payType", "2"));
            } else if ("R".equals(payType)) {
                tmpXElement.addChild(new XElement("payType", "3"));
            } else if ("O".equals(payType)) {
                tmpXElement.addChild(new XElement("payType", "4"));
            }
            tmpXElement.addChild(new XElement("charAccNo", ""));//手续费扣费账号 传空
            tmpXElement.addChild(new XElement("cryType", ""));//币种 手续费扣费账号所对应的币种必须一致 传空
            tmpXElement.addChild(new XElement("trxRemaPk1", reqForeignCurrSingle.singleDetail.transCode1));//交易编码及附言1

            int payAmountInt = Math.round(Float.parseFloat(reqForeignCurrSingle.singleDetail.payAmount));//汇出款小数点后一位四舍五入后取整的值
            int amout1Int = 0;//相应金额1后一位四舍五入后取整的值
            if (!StringHelper.isNullOrEmpty(reqForeignCurrSingle.singleDetail.transCode1)) {
                amout1Int = Math.round(Float.parseFloat(reqForeignCurrSingle.singleDetail.amout1));
            }
            int amout2Int = 0;//相应金额1后一位四舍五入后取整的值
            if (!StringHelper.isNullOrEmpty(reqForeignCurrSingle.singleDetail.transCode2)) {
                amout2Int = Math.round(Float.parseFloat(reqForeignCurrSingle.singleDetail.amout2));
            }
            if (amout1Int + amout2Int != payAmountInt) {
                amout1Int = payAmountInt + (payAmountInt - amout1Int - amout2Int);
            }
            //相应金额1 与汇出款金额进行校验，差距不能超过1.00；相应金额1和相应金额2之和须等于汇出款金额小数点后一位四舍五入后取整的值
            tmpXElement.addChild(new XElement("corrAmt1", StringHelper.isNullOrEmpty(reqForeignCurrSingle.singleDetail.transCode1) ? "" : amout1Int + ""));
            tmpXElement.addChild(new XElement("trxRemaPk2", reqForeignCurrSingle.singleDetail.transCode2));//交易编码及附言2  可空
            //相应金额2 交易编码及附言2为空时，相应金额2也必须为空
            tmpXElement.addChild(new XElement("corrAmt2", StringHelper.isNullOrEmpty(reqForeignCurrSingle.singleDetail.transCode2) ? "" : amout2Int + ""));
            if (StringHelper.isNullOrEmpty(reqForeignCurrSingle.singleDetail.contractNo)) {
                detail.respCode = "0";
                detail.respInfo = "合同号必填！";
                detail.reqSeqID = reqForeignCurrSingle.singleDetail.askNumber;
                detail.transState = "contractNoMustInput";
                detail.payInfoCode = detail.transState;
                return detail;
            }
            tmpXElement.addChild(new XElement("contractNo", reqForeignCurrSingle.singleDetail.contractNo));//合同号 ERP传入资金，必填，必传银行
            if (reqForeignCurrSingle.singleDetail.fundsProp.equals("1") && StringHelper.isNullOrEmpty(reqForeignCurrSingle.singleDetail.invoiceNo)) {
                detail.respCode = "0";
                detail.respInfo = "款项性质(业务类型)为贸易时，发票号必填！";
                detail.reqSeqID = reqForeignCurrSingle.singleDetail.askNumber;
                detail.transState = "fundsPropNotNull";
                detail.payInfoCode = detail.transState;
                return detail;
            }
            tmpXElement.addChild(new XElement("invoiceNo", reqForeignCurrSingle.singleDetail.invoiceNo));//发票号 业务类型为1:贸易时必输
            tmpXElement.addChild(new XElement("recformNo", reqForeignCurrSingle.singleDetail.businessNum));//备案表号 可空，指外汇局签发的银行凭以对外付款的各种批件或进口付汇备案表号
            tmpXElement.addChild(new XElement("froFlag", reqForeignCurrSingle.singleDetail.isDomestic.equals("0") ? "1" : "2"));//境内外标示 1：境外；2：境内  -->可空
            tmpXElement.addChild(new XElement("pdecNo", ""));//原申报号 char(22) ，可空，付款类型是3：退款时，必输 -不传（产品跟客户确认，目前没有退款类型）
            if (reqForeignCurrSingle.singleDetail.isDomestic.equals("1")) {//ATS请求“1”表示境内
                //付汇性质 char(1)，可空，不为空时必须满足X：保税区；E：出口加工区；D钻石交易所；A：其他特殊经济区；M：深加工转；O：其他，内外标识为境外时此字段必须为空，境内外标识为境内时必输
                tmpXElement.addChild(new XElement("payNature", reqForeignCurrSingle.singleDetail.payProperty));
            } else {
                tmpXElement.addChild(new XElement("payNature", ""));
            }
            if (reqForeignCurrSingle.singleDetail.fundsProp.equals("1")) {//本笔款项是否为保税货物项下付款 当业务类型为1：贸易时必输 数据字典为1：是；2：否 ，其他业务类型时必须为空
                tmpXElement.addChild(new XElement("bondFlag", reqForeignCurrSingle.singleDetail.isBondedGood.equals("1") ? "1" : "2"));
            } else {
                tmpXElement.addChild(new XElement("bondFlag", ""));
            }
            String curBankCode = getBankConfig().getMapValueByKey("currencyMapping2", reqForeignCurrSingle.singleDetail.payCur);//银行汇出款币种代码
            if (reqForeignCurrSingle.singleDetail.costMode.equals("OUR") && (curBankCode.equals("USD") || curBankCode.equals("EUR"))) {
                //当国内外费用承担为OUR：汇款人OUR且汇出款币种为美元或欧元时必输；当国内外费用承担不为汇款人OUR且汇出款币种不是美元或欧元时,是否需要做全额到账预扣费字段必须为空
                //？？？是否需要做全额到账预扣费 1：是；2：否
                tmpXElement.addChild(new XElement("ovrchgFlg", "2"));//ATS不传该值，暂时默认  否
            } else {
                tmpXElement.addChild(new XElement("ovrchgFlg", ""));
            }
            if (reqForeignCurrSingle.singleDetail.fundsProp.equals("1")) {
                //？？？购汇类型 业务类型为1:贸易时，购汇类型必须为空；业务类型为4：同名划转时，购汇类型必须上送470-其他；业务类型为2：服务贸易，3：资本时，购汇类型必输 可空不传
                tmpXElement.addChild(new XElement("nontradeType", ""));
            } else {
                tmpXElement.addChild(new XElement("nontradeType", "470"));//ATS不传该值，暂时默认 "470"
            }

            tmpXElement.addChild(new XElement("fileNm", ""));//文件名称 char(122)，可空-->---可空不传
            xmlWriter.writeXElement(tmpXElement);
            xmlWriter.writeEndDocument();

            String[] tmpStrRet = sendToBank(xmlWriter.toXmlString());//发送银行
            if (tmpStrRet[0].length() == 0) {
                StringBuilder tmpSbMsg = new StringBuilder();
                //解析银行返回
                XmlTextReader tmpBkReader = loadBankRespXmlReader(tmpStrRet[1], tmpSbMsg);
                if (tmpBkReader != null) {
                    //将业务类型与流水号存入数据库，查询时候使用
                    String uuid = UUID.randomUUID().toString().replaceAll("-", "");
                    JDBCHelper.update(conn, INSERTRECEIPT, new Object[]{uuid, reqForeignCurrSingle.reqHeader.bankCode, reqForeignCurrSingle.singleDetail.askNumber, reqForeignCurrSingle.singleDetail.fundsProp, Format.Date8Format.format(new Date())});
                    detail.respCode = "0";
                    detail.respInfo = tmpBkReader.getFirstText("/stream/statusText");
                    detail.reqSeqID = reqForeignCurrSingle.singleDetail.askNumber;
                    detail.transState = tmpBkReader.getFirstText("/stream/status") + "+submit";
                    detail.payInfoCode = detail.transState;
                } else {
                    detail.respCode = "-1";
                    detail.respInfo = tmpSbMsg.toString();
                }
            } else if (tmpStrRet[0].equals(ConnState.FAIL)) {
                detail.respCode = "0";
                detail.respInfo = tmpStrRet[1];
                detail.reqSeqID = reqForeignCurrSingle.singleDetail.askNumber;
                detail.transState = PaymentState.FAIL_Payment;
                detail.payInfoCode = tmpStrRet[0];
            } else {
                detail.respCode = "-1";
                detail.respInfo = tmpStrRet[1];
            }
        } catch (Exception e) {
            detail.respCode = "-1";
            detail.respInfo = "外币汇款出现异常!";
            WriteBankLogLn("外币汇款出现异常,异常信息:" + e.getMessage());
            e.printStackTrace();
        } finally {
            conn.close();
        }
        return detail;
    }

    /**
     * 汇出汇款申请查询
     *
     * @param reqQryForeignCurrSingle
     * @return
     * @throws Exception
     */
    @Override
    public RetAtsForeignCurrSingle qryForeignCurrPay(ReqQryForeignCurrSingle reqQryForeignCurrSingle) throws Exception {
        RetAtsForeignCurrSingle retAts = new RetAtsForeignCurrSingle(reqQryForeignCurrSingle.reqHeader);
        RetAtsForeignCurrPayDetail tmpRetDetail = new RetAtsForeignCurrPayDetail();
        Connection conn = FGBiz.getLocalDbConn();
        try {
            CITIC01Header bankHeader = new CITIC01Header();
            bankHeader.action = "DLOUTAQY";
            XmlTextWriter xmlWriter = new XmlTextWriter();//发银行报文的XML对象
            xmlWriter.writeStartDocByDeclaration("<?xml version=\"1.0\" encoding=\"GBK\"?>");
            xmlWriter.writeStartElement("stream");
            xmlWriter.writeElementString("action", bankHeader.action);
            xmlWriter.writeElementString("userName", bankFront.loginName);//登录名
            xmlWriter.writeElementString("clientID", reqQryForeignCurrSingle.askNumber);
//            xmlWriter.writeElementString("clientID", reqQryForeignCurrSingle.reqHeader.transSeqID);
            Map<String, Object> map = JDBCHelper.execQuerySingle(conn, SELECTRECEIPT, new Object[]{reqQryForeignCurrSingle.askNumber, reqQryForeignCurrSingle.reqHeader.bankCode});
            if (map.size() == 0) {
                tmpRetDetail.respCode = "-1";
                tmpRetDetail.respInfo = "流水号:" + reqQryForeignCurrSingle.askNumber + "，没有交易映射！";
                retAts.writeRetDetail(tmpRetDetail);
                return retAts;
            }
            xmlWriter.writeElementString("bsnType", map.get("RESERVE1").toString());//业务类型1：贸易；2：服务贸易；3：资本；4：同名划转（通过DSP数据库映射）
            xmlWriter.writeElementString("tranType", "01");//交易类型 01：已提交银行申请；02：未提交银行申请  现只支持01：已提交银行申请
            xmlWriter.writeElementString("ouremNo", "");//汇出汇款流水号
            xmlWriter.writeElementString("remCryType", "");//汇款币种 可空
            xmlWriter.writeElementString("rcvAcc", "");//收款人账号 可空
            xmlWriter.writeElementString("minAmt", "");//最小金额 可空
            xmlWriter.writeElementString("maxAmt", "");//最大金额  可空
            xmlWriter.writeElementString("startDate", map.get("TRANSDATE").toString());//起始日期 YYYYMMDD
            xmlWriter.writeElementString("endDate", map.get("TRANSDATE").toString());//截止日期 YYYYMMDD
            xmlWriter.writeElementString("pageNumber", "20");//请求记录条数int，最大为20
            xmlWriter.writeElementString("startRecord", "1");//起始记录号
            xmlWriter.writeEndDocument();

            String[] tmpStrRet = sendToBank(xmlWriter.toXmlString());
            if (tmpStrRet[0].length() == 0) {
                StringBuilder tmpSbMsg = new StringBuilder();
                XmlTextReader tmpBkReader = loadBankRespXmlReader(tmpStrRet[1], tmpSbMsg);
                if (tmpBkReader != null) {
                    String tmpStatus = tmpBkReader.getFirstText("/stream/status");
                    String tmpStatusText = tmpBkReader.getFirstText("/stream/statusText");
                    if (tmpStatus != null && tmpStatus.equals("AAAAAAA")) {
                        if (tmpBkReader.read("/stream/list")) {
                            if (tmpBkReader.readedXElement.getAttrValue("name").equals("userDataList")) {
                                tmpRetDetail.reqSeqID = reqQryForeignCurrSingle.askNumber;
                                if (StringHelper.isNullOrEmpty(tmpBkReader.readedXElement.getSingleText("row/stt"))) {
                                    tmpRetDetail.respCode = "0";
                                    tmpRetDetail.respInfo = "无该流水信息";
                                    tmpRetDetail.transState = "stt+null";
                                    tmpRetDetail.payInfoCode = tmpRetDetail.transState;
                                } else {
                                    tmpRetDetail.respCode = "0";
                                    tmpRetDetail.respInfo = tmpStatusText + ",查询请求处理成功";
                                    tmpRetDetail.transAmt = tmpBkReader.readedXElement.getSingleText("row/remAmt");
                                    tmpRetDetail.transState = "stt+" + tmpBkReader.readedXElement.getSingleText("row/stt");
                                    tmpRetDetail.payInfoCode = tmpRetDetail.transState;
                                }
                            } else {
                                tmpRetDetail.respCode = "-1";
                                tmpRetDetail.respInfo = "未找到userDataList的list";
                            }
                        } else {
                            tmpRetDetail.respCode = "-1";
                            tmpRetDetail.respInfo = "未找到/stream/list";
                        }
                    } else if (tmpStatus != null && tmpStatus.length() > 0) {
                        if ("ED12001".equals(tmpStatus) || "ED12002".equals(tmpStatus)) {//系统登录中,请稍候再试.
                            tmpRetDetail.respCode = "-1";
                        } else {
                            tmpRetDetail.respCode = "0";
                        }
                        tmpRetDetail.reqSeqID = reqQryForeignCurrSingle.askNumber;
                        tmpRetDetail.respInfo = tmpStatusText;
                        tmpRetDetail.transState = tmpStatus;
                        tmpRetDetail.payInfoCode = tmpRetDetail.transState;
                    } else {
                        tmpRetDetail.respCode = "-1";
                        tmpRetDetail.respInfo = tmpStatusText;
                    }
                } else {
                    tmpRetDetail.respCode = "-1";
                    tmpRetDetail.respInfo = tmpSbMsg.toString();
                }
            } else {
                tmpRetDetail.respCode = "-1";
                tmpRetDetail.respInfo = tmpStrRet[1];
            }
        } catch (Exception e) {
            tmpRetDetail.respCode = "-1";
            tmpRetDetail.respInfo = "汇出汇款申请查询，出现异常！";
            WriteBankLogLn("汇出汇款申请查询，出现异常,异常信息：" + e.getMessage());
            e.printStackTrace();
        }
        retAts.writeRetDetail(tmpRetDetail);
        return retAts;
    }
}
